
import {
  BuildContractParam, CompileContractParam, RunContractParam,
  PreferenceRequest, AutocomplateRequest, SaveParam, BuildParam,
  FmtParam, RenameFileParam, DeclParam, IdeServer, DeployContractParam, InvokeContractParam, AuditParam
} from '@ide/types/ideServer';
import { TreeItem } from '@ide/types/tree';
import {
  contractCompile, contractHasBuild, contractInvokeAll,
  contractMethod, contractNames, contractRunBuild, getContractFiles,
  deployContractList, getContractFile, deployContract,
  hasDeployContractList, newFile, preference, removeFile,
  renameFile, pullnotify, file, saveFile, outline, autocomplete,
  newContract, build, fmt, goModuleFiles, importFiles, decl, exportFile, outputWs, filesWs, audit
} from '../api';
import { versionConfig } from '@/config';


function formatTree(files: any[]): TreeItem[] {
  return files.map(item => {
    const { name, type, children, path, isGOAPI, isParent, canNotRenameAble } = item;
    return {
      id: path,
      name: name ?? 'root',
      content: name ?? 'root',
      type: type === 'f' ? 'file' : 'folder',
      path,
      editable: !isGOAPI,
      isParent,
      children: children.length ? formatTree(children) : undefined,
      canNotRenameAble
    };
  });
}

const config = {
  pluginDownloadPage: 'https://git.chainmaker.org.cn/chainmaker/chainmaker-smartplugin/-/releases',
  requestPath: versionConfig.serverHost
};

const watch: {
  [key: string]: any
} = {
  output: undefined,
  files: undefined
};

const server: IdeServer = {
  ...config,
  // getInitData: async () => {
  //   const data = await index({});
  //   if (data.code === 0 && data?.data) {
  //     return data.data;
  //   } else {
  //     throw new Error(data.msg);
  //   }
  // },
  getContractFiles: async (params: {}) => {
    const data = await getContractFiles(params);
    if (data.code === 0 && data?.data) {
      return formatTree(data.data.children);
    } else {
      throw Error(data.message);
    }
  },
  goModuleFiles: async (contractName?: string) => {
    const data = await goModuleFiles({ contractName });
    if (data.code === 0 && data?.data) {
      return formatTree([data.data]);
    } else {
      throw Error(data.message);
    }
  },
  getContractHasBuild: async (contractNames?: string[]) => {
    const data = await contractHasBuild({ contractNames });
    if (data.code === 0 && data?.data) {
      return data.data;
    } else {
      throw new Error(data.msg);
    }
  },
  newFile: async (param: {
    path?: string;
    fileType?: 'd' | 'f'
  }) => {
    const data = await newFile(param);
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  getFileContent: async (path: string) => {
    const data = await file({ path });
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  saveFile: async (param: SaveParam) => {
    const data = await saveFile(param);
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  fileOutline: async (code: string) => {
    const data = await outline({ code });
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  removeFile: async (path: string) => {
    const data = await removeFile({
      path
    });
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  renameFile: async (param: RenameFileParam) => {
    const data = await renameFile(param);
    if (data.code === 0) {
      return data.data;
    }
    throw Error(data.msg);
  },
  importFiles: async (param: FormData) => {
    const { code, data, msg } = await importFiles(param);
    if (code === 0) {
      return data;
    }
    throw Error(msg);
  },
  exportFile: async (path: string) => {
    const { code, data, msg } = await exportFile({ path });
    if (code === 0) {
      return data;
    }
    throw Error(msg);
  },
  queryDeployContractList: async () => {
    const data = await deployContractList({});
    if (data.code === 0 && data?.data) {
      return data.data.deployList;
    } else {
      throw new Error(data.msg);
    }
  },
  getContractNames: async () => {
    const { code, data } = await contractNames({});
    if (code === 0 && data?.length !== 0) {
      return data.map((item:any) => ({
        path: item.path,
        contractName: item.name
      }));
    } else {
      throw Error(data.message);
    }
  },
  getContractMethod: async (path: string) => {
    const { code, data } = await contractMethod({ path });
    if (code === 0 && data?.length !== 0) {
      return data;
    } else {
      throw Error(data.message);
    }
  },
  postContractRunBuild: async (param: BuildContractParam) => {
    const { code, data, msg } = await contractRunBuild(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  postContractInvokeAll: async (param: RunContractParam) => {
    const { code, data, msg } = await contractInvokeAll(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  postContractCompile: async (param: CompileContractParam) => {
    const { code, data, msg } = await contractCompile(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  getContractFile: async (path: string, needFile = true) => {
    const data = await getContractFile({ path });
    if (needFile) {
      const file = new File([data], path.match(/[^\\/]+$/)?.[0] ?? '-');
      return file;
    }
    return data;
  },
  deployContract: async (contractName: string) => {
    const { code, msg, data } = await deployContract({ contractName });
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  hasDeployContractList: async () => {
    const { code, msg, data } = await hasDeployContractList({});
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data.hasDeployList.map((item:any) => ({
        contractName: item.name,
        ...item
      }));
    }
  },
  preference: async (params: PreferenceRequest) => {
    const { code, msg, data } = await preference(params);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  pullnotify: async () => {
    const { code, msg, data } = await pullnotify({});
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  addFileChangeListener: (callback) => {
    watch.files = filesWs({});
    // watch.files.addEventListener('error', (error:any) => {
    //   message.error({
    //     content: error.toString()
    //   });
    // });
    // watch.files.addEventListener('close', () => {
    //   message.warning({
    //     content: 'socket会话已关闭'
    //   });
    // });
    watch.files.addEventListener('message', (e:any) => {
      callback(e);
    });
  },
  addOutputListener: (output) => {
    watch.output = outputWs({});
    // watch.output.addEventListener('error', (error:any) => {
    //   message.error({
    //     content: error.toString()
    //   });
    // });
    // watch.output.addEventListener('close', () => {
    //   message.warning({
    //     content: 'socket会话已关闭'
    //   });
    // });
    watch.output.addEventListener('message', (e:any) => {
      output(e);
    });
  },
  removeOutputListener: () => {
    // clearTimeout(watch.output);
    watch.client?.close();
  },
  autocomplete: async (param: AutocomplateRequest) => {
    const options = await autocomplete(param);
    if (options && options[0] && options[1]) {
      return options[1].map((item: any) => ({
        type: item.type || 'constant',
        label: item.name,
        detail: item.class,
        info: item.package
      }));
    }
    return [];
  },
  newContract: async (contractName: string) => {
    const { code, msg, data } = await newContract({ contractName });
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  build: async (param: BuildParam) => {
    return await build(param);
  },
  fmt: async (param: FmtParam) => {
    const { code, msg, data } = await fmt(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data.code;
    }
  },
  pluginIsReady: async () => {
    return Boolean((window as any).chainMaker);
  },
  pluginDeployContract: async (param: DeployContractParam) => {
    const { contractName, contractVersion, contractFile, runtimeType, params, accountAddress } = param;
    return (window as any).chainMaker.sendRequest('createUserContract', {
      body: {
        contractName,
        contractVersion,
        contractFile,
        runtimeType, // 'WASMER',
        params: params.reduce((val:any, item) => {
          val[item.key] = item.value;
          return val;
        }, {})
      },
      accountAddress,
      contractName
    });
  },
  pluginInvokeContract: async (param: InvokeContractParam) => {
    const { contractName, method, params } = param;
    return (window as any).chainMaker.sendRequest('invokeUserContract', {
      body: {
        contractName,
        method,
        params: params.reduce((val:any, item) => {
          val[item.key] = item.value;
          return val;
        }, {})
      },
      contractName
    }, (res:any) => {
      console.log(res);
    });
  },
  pluginRequest: async (param: any) => {
    return (window as any).chainMaker.sendRequest(param);
  },
  pluginIsConnected: () => {
    return !!(window as any).chainMaker;
  },
  decl: async (param: DeclParam) => {
    const { code, msg, data } = await decl(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  },
  getDownloadPath: async (name: string) => {
    return `${versionConfig.serverHost}file/getContractFile?path=${name}`;
  },
  auditContract: async (param: AuditParam) => {
    const { code, msg, data } = await audit(param);
    if (code !== 0) {
      throw new Error(msg);
    } else {
      return data;
    }
  }
};
export default server;
